/***************************************************************************************************
  *Copyright(C),2010-2017,Sumscope
  *FileName	:  pinyin_search_engine.h
  *Author	:  scofined.qi
  *Version	:  1.0
  *Date		:  2017/06/04
  *Desc		:  //用于主要说明此程序文件完成的主要功能
  *Relation :  
  *Others	:  //其他内容说明
  *Function :  //主要函数列表，每条记录应包含函数名及功能简要说明
  *History	:  //修改历史记录列表，每条修改记录应包含修改日期、修改者及修改内容简介
***************************************************************************************************/
#pragma once
#include "pinyin_search_define.h"
#include "pinyin_search_key.h"
#include "pinyin_search_set.h"
#include "pinyin_search_idvec.h"
#include "pinyin_search_idstore.h"
#include "pinyin_search_idfile.h"
#include "../pinyin_search.h"
#include <core/time/time.h>
#include <core/strings/WideString.h>
#include <core/strings/string_convert.h>
#include <core/strings/string_util.h>
#include <core/instance/singleton.h>
#include <core/container/CHashMap.h>
#include <core/sync/lock.h>

namespace qb{
	namespace base{
		class StringPage;
		namespace internal{
			class BondChangeBuffer;
			class IndexListMap
			{
			public:
                typedef qb::base::CHashMap<InverseKey, IndexIdRange*>	InverseSetPtrHashMap;
				typedef InverseSetPtrHashMap::iterator iterator;
				typedef map < InverseKey, IndexIdRange* > InverseSetPtrMap;
			protected:
				InverseSetPtrHashMap	m_hashmap;			// 哈希表
				InverseSetPtrMap		m_map;				// 作对比测试用
			public:
				IndexListMap(int capcity);
				~IndexListMap();
				IndexIdRange* Find(const InverseKey& key);
				void Insert(const InverseKey& key, InverseSet* isets);
				iterator begin(){ return m_hashmap.begin(); }
				iterator end(){ return m_hashmap.end(); }
				int size()const{ return m_hashmap.Count(); }
				int capcity()const{ return m_hashmap.Capcity(); }
				int bytes()const;
			};
            class SpellSearchImpl : public ISpellSearch, public qb::base::Singleton<SpellSearchImpl>{
                typedef qb::base::SpellSearch::Listener Listener;
			public:
				enum kPredictMode{		// 每个索引键的预估尺寸的模式
					kPredictModeNone,	// 不适用预估尺寸
					kPredictModeArray,	// 使用全部数组的模式,对应于KeyStat的MagicKeyCapcity
					kPredictModeSlot,	// 使用插槽模式,对应于KeyStat的Magic
				};
			protected:
                typedef qb::base::strinfo strinfo;
                typedef qb::base::StringUtil StringUtil;
                typedef qb::base::HighResTime HighResTime;
                typedef qb::base::BaseString BaseString;
				typedef InverseSet	IndexSet;
				typedef std::map<InverseKey, int> PredictMap;
				class InverseKeySet : public std::set<InverseKey>{
					int		m_start_index;
				public:
					InverseKeySet() :m_start_index(0){}
					void SetStart(int start){ start = start <= 0 ? 0 : start; m_start_index = start; }
					int  GetStart()const{ return m_start_index; }
				};
				class KeyCache{
					typedef CHashMap<wchar_t, InverseKeySet*> CharInverseKeyMap;
					CharInverseKeyMap		m_cache;
					InverseKeySet			m_temp;
				public:
					KeyCache(){}
					~KeyCache();
					void AddKey(const InverseKey& key);
					const InverseKeySet* GetKeys(const wstring& text);
					InverseKeySet* GetKeySet(wchar_t code);
					void Dump();
				};
				IndexListMap				m_indexes;		// key到IndexIdRange的映射关系
				IndexListMap				m_indexes2;		// 只用于有2个字符的key;
				InverseSet					m_firstset;		// 第一个键值搜索的结果集
				InverseSet					m_tempset;		// 第二个以及后续键值搜索的结果集
				IndexIdStore				m_firststore;	// 存储当前搜索的IndexId序列
				IndexIdStore				m_currentstore;	// 
				KeyCache					m_keycache;
				PredictMap					m_predictmap;	// 用于预估每个InverseKey可能对应多少个值
				int							m_predict_min;	// 当前的尺寸预估的最小值(初始默认值)
				kPredictMode				m_predict_mode;	// 当前的尺寸预估模式
				wstring						m_lastkey;
                qb::base::CSLock			m_lock;			//
				int							m_max_index;
				int							m_max_count2;
				int							m_max_count;	// 
				int							m_keylen;		// 
				unsigned int				m_last_tick;
                qb::base::WideString		m_comma;		// 用于分隔pinyin.cpp产生的拼音串中间的逗号
				bool						m_initialized;	//
				bool						m_deleteset;	// 用于控制BuildIndex之后,是否删除IndexIdRange中的内存集合m_memory_set,默认true
				bool						m_flag_check;	// 用于控制是否开启内部测试,通过配置变量控制,默认false,开启后会影响性能
				bool						m_flag_usingset;// 默认为false,表示使用映射文件,否则将使用内存set
				bool						m_flag_searchtag;
				bool						m_flag_verboscheck;
				bool						m_flag_keycache;
				bool						m_flag_endcode;
                qb::base::CConvertFast		m_convert;		// 用于转码
                qb::base::CConvertFast		m_convert_find;
				IndexIdFile					m_file;			// 映射文件
			public:
				SpellSearchImpl(int capcity = 60000,int nPageCount=32,bool verbos=false);
				~SpellSearchImpl();
				void Dump();

				bool IsReady()const{ return m_initialized; }
				void SetReady(){ m_initialized = true; }
				void SetFlag(const char* name, bool flag);
				bool GetFlag(const char* name)const;
				virtual void BuildIndex(bool diskless)override;
                virtual void FindBonds(const std::wstring& text, Listener* listener);
				virtual bool AddBondChange(BondChangeBuffer* change);
                virtual void GetAllKeys(std::vector<std::wstring>& keys);
			protected:
				InverseSet* FindInverseSet(const InverseKey& key, InverseSet* target);
				IndexIdStore* UpdateFirstStore(const InverseKey& key);
				IndexIdStore* UpdateFirstStoreWithDoubleKey(const InverseKey& key);
                IndexIdStore* UpdateFirstStoreByCheckLastKey(const std::wstring& key, int& pos);
                IndexIdStore* FindIndexBySpellMatch(const std::wstring& text);
                void FindBondIndexes(const std::wstring& text, IndexIdVec& first, bool log);
                void FindBondsWithLessKey(const std::wstring& text, Listener* listener);
				void RemoveIndexForSentence(int index, const wchar_t* sentence, int len, bool split);
				void RemoveIndexForKey(int index, const InverseKey& key);
				void AddIndexForSentence(int index, const wchar_t* sentence, int len,bool split);
				void AddIndexForKey(int index, const InverseKey& key);
				bool IntersectWithKey(IndexIdVec& first, const InverseKey& rkey, int step,bool log,int& ncount);
			protected://针对只有2个字符的情况,只限定于kChangeTypeName, kChangeTypeNameEn 和 kChangeTypeCode
				void AddIndexForDoubleKey(int index, const InverseKey& key);
				void RemoveIndexForDoubleKey(int index, const InverseKey& key);
			protected://内部功能测试接口,必须使用宏BASSERT_SPELL来关闭和开启
				bool UseMappingSet()const;
				void CheckAll();
				bool CheckIndexForKey(int index, const InverseKey& key);
				int PredictCount(const InverseKey& key);
			};

		}
	}
}
